﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Text.RegularExpressions;

namespace PaymentHelper.Core.ViewEmbeddedHandler
{
    public class AssemblyLoader
    {
        private string _assemblySkipLoadingPattern = "^System|^mscorlib|^Microsoft|^CppCodeProvider|^VJSharpCodeProvider|^WebDev|^Castle|^Iesi|^log4net|^NHibernate|^nunit|^TestDriven|^MbUnit|^Rhino|^QuickGraph|^TestFu|^Telerik|^ComponentArt|^MvcContrib|^AjaxControlToolkit|^Antlr3|^Remotion|^Recaptcha";
        private string _assemblyRestrictToLoadingPattern = ".*";
        private IList<string> _assemblyNames;
        private static AssemblyLoader _instance;

        private AssemblyLoader()
        {
            _assemblyNames = new List<string>();
        }

        public static AssemblyLoader Instance
        {
            get 
            {
                if (_instance == null)
                    _instance = new AssemblyLoader();

                return _instance;
            }
        }

        public IList<Assembly> GetAssemblies()
        {
            var addedAssemblyNames = new List<string>();
            var assemblies = new List<Assembly>();

            AddAssembliesInAppDomain(addedAssemblyNames, assemblies);

            return assemblies;
        }

        /// <summary>
        /// Add all assemblies which match the configured patern in App Domain
        /// </summary>
        /// <param name="addedAssemblyNames"></param>
        /// <param name="assemblies"></param>
        private void AddAssembliesInAppDomain(List<string> addedAssemblyNames, List<Assembly> assemblies)
        {
            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (AssemblyMatch(assembly.FullName))
                {
                    if (!addedAssemblyNames.Contains(assembly.FullName))
                    {
                        addedAssemblyNames.Add(assembly.FullName);
                        assemblies.Add(assembly);
                    }
                }
            }
        }

        /// <summary>
        /// Adds specificly configured assemblies
        /// </summary>
        /// <param name="addedAssemblyNames"></param>
        /// <param name="assemblies"></param>
        //private void AddConfiguredAssemblies(List<string> addedAssemblyNames, List<Assembly> assemblies)
        //{
        //    foreach (string assemblyName in _assemblyNames)
        //    {
        //        Assembly assembly = Assembly.Load(assemblyName);
        //        if (!addedAssemblyNames.Contains(assembly.FullName))
        //        {
        //            addedAssemblyNames.Add(assembly.FullName);
        //            assemblies.Add(assembly);
        //        }
        //    }
        //}

        protected bool AssemblyMatch(string assemblyFullName)
        {
            bool isMatch = false;

            isMatch = !Matches(assemblyFullName, _assemblySkipLoadingPattern) &&
                Matches(assemblyFullName, _assemblyRestrictToLoadingPattern);

            return isMatch;
        }

        protected bool Matches(string assemblyFullName, string pattern)
        {
            return Regex.IsMatch(assemblyFullName, pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled);
        }

        public static Assembly LoadResourceAssembly(string name)
        {
            try
            {
                return AppDomain.CurrentDomain.GetAssemblies()
                    .Where(a => a.FullName.Equals(name, StringComparison.InvariantCultureIgnoreCase))
                    .FirstOrDefault();
            }
            catch
            {
                return null;
            }
        }
    }
}
